package com.topisv.tms.service.stock.instorage;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.hibernate.ejb.criteria.predicate.ComparisonPredicate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.topisv.tms.entity.AreaGroup;
import com.topisv.tms.entity.Customers;
import com.topisv.tms.entity.EdiGoodsSku;
import com.topisv.tms.entity.User;
import com.topisv.tms.entity.stock.instorage.InstorageBill;
import com.topisv.tms.entity.stock.instorage.InstorageCountItem;
import com.topisv.tms.entity.stock.instorage.InstorageCountTask;
import com.topisv.tms.entity.stock.instorage.InstorageLog;
import com.topisv.tms.entity.stock.instorage.InstorageUpDispatchTask;
import com.topisv.tms.entity.stock.instorage.InstorageUpTask;
import com.topisv.tms.entity.stock.instorage.InstorageUpTaskItem;
import com.topisv.tms.entity.stock.instorage.pre.InstorageBillItemPre;
import com.topisv.tms.entity.stock.instorage.pre.InstorageBillPre;
import com.topisv.tms.entity.stock.instorage.pre.PreInBill;
import com.topisv.tms.entity.stock.oustorage.OutstorageBillItem;
import com.topisv.tms.exception.ErrorCode;
import com.topisv.tms.exception.InStorageBillErrorCode;
import com.topisv.tms.exception.PaiUException;
import com.topisv.tms.repository.AreaGroupDao;
import com.topisv.tms.repository.CustomersDao;
import com.topisv.tms.repository.EdiGoodsSkuDao;
import com.topisv.tms.repository.UserDao;
import com.topisv.tms.repository.stock.instorage.InstorageBillDao;
import com.topisv.tms.repository.stock.instorage.InstorageCountItemDao;
import com.topisv.tms.repository.stock.instorage.InstorageCountTaskDao;
import com.topisv.tms.repository.stock.instorage.InstorageLogDao;
import com.topisv.tms.repository.stock.instorage.InstorageUpDispatchTaskDao;
import com.topisv.tms.repository.stock.instorage.InstorageUpTaskDao;
import com.topisv.tms.repository.stock.instorage.InstorageUpTaskItemDao;
import com.topisv.tms.repository.stock.outstorage.OutstorageBillItemDao;
import com.topisv.tms.repository.stock.preInstorage.InstorageBillItemPreDao;
import com.topisv.tms.repository.stock.preInstorage.InstorageBillPreDao;
import com.topisv.tms.utils.EdiOrderUtil;
import com.topisv.tms.utils.WmsContants;
import com.topisv.tms.utils.enums.InstorageStatusEnums;
import com.topisv.tms.utils.enums.PYOrderType;
import com.topisv.tms.utils.enums.StatusEnums;
import com.topisv.tms.utils.rule.TMSTransportRule;

/**
 * 入库点收任务_service
 * @author ch
 *
 */
@Component
@Transactional(readOnly = true)
public class InstorageCountTaskService {
	
	@Autowired
	private InstorageCountTaskDao instorageCountTaskDao;
	@Autowired
	private CustomersDao customersDao;
	@Autowired
	private AreaGroupDao areaGroupDao;
	@Autowired
	private InstorageBillDao instorageBillDao;
	@Autowired
	private UserDao userDao;
	@Autowired
	private InstorageLogDao instorageLogDao;
	@Autowired
	private InstorageCountItemDao instorageCountItemDao;
	@Autowired
	private InstorageUpTaskDao instorageUpTaskDao;
	@Autowired
	private InstorageBillPreDao instorageBillPreDao;
	@Autowired
	private InstorageBillItemPreDao instorageBillItemPreDao;
	@Autowired
	private OutstorageBillItemDao outstorageBillItemDao;
	@Autowired
	private InstorageUpDispatchTaskDao instorageUpDispatchTaskDao;
	@Autowired
	private InstorageUpTaskItemDao instorageUpTaskItemDao;
	@Autowired
	private EdiGoodsSkuDao ediGoodsSkuDao;
	@Autowired
    private JdbcTemplate jdbcTemplate;
	
	/**
	 * 查询点收任务
	 * @param param
	 * @return
	 */
	public List<InstorageCountTask> loadTaskByParam(Map<String, Object> param) {
		Specification<InstorageCountTask> spec = getWhereClause(param);
		List<InstorageCountTask> taskList = this.instorageCountTaskDao.findAll(spec);
		this.setDetail(taskList);
		return taskList;
	}
	
	private void setDetail(List<InstorageCountTask> taskList){
		for (InstorageCountTask task : taskList) {
			
			//商家
			String customerCode=task.getCustomerCode();
			Customers customer=this.customersDao.findByCustomerCode(customerCode);
			task.setCustomer(customer);
			
			//仓库
			String warehouseCode=task.getWarehouseCode();
			AreaGroup warehouse=this.areaGroupDao.findByGroupCode(warehouseCode);
			task.setWarehouse(warehouse);
			
			//入库单
			String billCode=task.getBillCode();
			InstorageBill bill=this.instorageBillDao.loadBillByCode(billCode);
			task.setBill(bill);
			
			//作业员
			String workerUuid=task.getWorkerUuid();
			User worker=this.userDao.findByJobuuid(workerUuid);
			task.setWorker(worker);
			
		}
	}
	
	/**
	 * 查询条件封装
	 * @param param
	 * @return
	 */
	private Specification<InstorageCountTask> getWhereClause(final Map<String, Object> param) {
		return new Specification<InstorageCountTask>(){
			@Override
		    public Predicate toPredicate(Root<InstorageCountTask> r, CriteriaQuery<?> q, CriteriaBuilder cb) {
		      Predicate pre = cb.conjunction();
		      
		      //商家组
		      String customerCodes=(String) param.get("customerCodes");
		      if(StringUtils.isNotBlank(customerCodes)) {
		    	  String[] customerCodeSplit = customerCodes.split(":");
				  ComparisonPredicate[] tempCustomerCode = new ComparisonPredicate[customerCodeSplit.length];
				  int i = 0;
				  for (String _customerCode : customerCodeSplit) {
					 tempCustomerCode[i] = (ComparisonPredicate) cb.equal(r.get("customerCode"), _customerCode);
					 i++;
				  }
				  pre.getExpressions().add(cb.or(tempCustomerCode));
		      }
			  
		      //仓库组
		      String areagroups=(String) param.get("areagroups");
		      if(StringUtils.isNotBlank(areagroups)) {
		    	  String[] areagroupSplit = areagroups.split(":");
				  ComparisonPredicate[] areagroupArray = new ComparisonPredicate[areagroupSplit.length];
				  int j = 0;
				  for (String _areagroup : areagroupSplit) {
						areagroupArray[j] = (ComparisonPredicate) cb.equal(r.get("warehouseCode"), _areagroup);
						j++;
				  }
				  pre.getExpressions().add(cb.or(areagroupArray));
			  }
		      //单号
		      String countbillCode=(String) param.get("countbillCode"); 
		      if(StringUtils.isNotEmpty(countbillCode)){
		    	  pre.getExpressions().add(cb.equal(r.get("billCode"),countbillCode));
		      }
		      //状态
		      String status=(String) param.get("status"); 
		      if(StringUtils.isNotEmpty(status)){
		    	  
		    	  if("myTask".equals(status)){ //我的任务
		    		  String countstatus=(String) param.get("countstatus"); 
		    		  if(StringUtils.isNotEmpty(countstatus)){
		    			  pre.getExpressions().add(cb.equal(r.get("status"),countstatus));
		    		  }else{
		    			  pre.getExpressions().add(cb.or(
			    				  cb.equal(r.get("status"),"token"),
			    				  cb.equal(r.get("status"),"doing")
			    		  ));
		    		  }
		    	  }else{
		    		  pre.getExpressions().add(cb.equal(r.get("status"),status));
		    	  }
		    	 
			  }
		      
		      //作业员
		      if(param.get("workerUuid")!=null){
		    	  String workerUuid=(String) param.get("workerUuid");
				  pre.getExpressions().add(cb.equal(r.get("workerUuid"),workerUuid));
			  }	
		      
		      return pre;
		    }
		  };
       }

	
	/**
	 * 领取任务
	 * @param taskId 任务ID
	 * @param jobuuid 任务执行人
	 * @throws Exception 
	 */
	@Transactional(readOnly = false, rollbackFor=Exception.class)
	public String takeTask(Long taskId, String jobuuid) throws Exception {
		
		try {
			InstorageCountTask task=this.instorageCountTaskDao.findOne(taskId);
			InstorageBill bill=this.instorageBillDao.loadBillByCode(task.getBillCode());
			
			//已取消的不能领取
			if(InstorageStatusEnums.CANCEL.getType().equals(bill.getStatus())){
				throw new PaiUException(ErrorCode.ORDER_CANCELED_ERROR, new String[] { bill.getBillCode() });
			}
			
			User worker=this.userDao.findByJobuuid(jobuuid);
			Date now=new Date();
			
			//任务已被领取
			String status=task.getStatus();
			if(!"undo".equals(status)){
				return "token";
			}
			
			//修改任务状态
			task.setWorkerUuid(jobuuid);
			task.setStatus("token"); //任务状态 （undo.创建点收任务 token:领取任务 doing:点收中 finish.点收完成）
			this.instorageCountTaskDao.save(task);
			
			
			bill.setStatus("2");//入库状态 （0:待登记 (调拨货品已出库，尚未入库) 1.入库登记  2.领取点收任务   3.点收完成   4.领取上架任务   5.上架完成 ）
			this.instorageBillDao.save(bill);
			
			//入库日志
			InstorageLog log=new InstorageLog();
			log.setBillCode(task.getBillCode());
			log.setWorkerUuid(jobuuid);
			log.setInfo(worker.getRealname()+"领取点收任务");
			log.setWorkTime(now);
			log.setWorkType("takeCountTask"); //操作类型 ( sign.登记入库单 takeCountTask.领取点收任务 finishCount.点收完成 taskUpTask.领取上架任务 finishUp.上架完成 )
			this.instorageLogDao.save(log);
			
			return "success";
		
		} catch (Exception e) {
			throw new Exception(e);
		}
	}

	public InstorageCountTask loadById(Long taskId) {
		return this.instorageCountTaskDao.findOne(taskId);
	}
	
	@Transactional(readOnly = false, rollbackFor=Exception.class)
    public Map<String, Object> countNew(String taskCode, String sku, Integer num, String errorFlag) throws Exception {
        try { 
            
            Map<String, Object> resultMap = new HashMap<String, Object>();
            //修改任务状态
            InstorageCountTask task=this.instorageCountTaskDao.loadByTaskCode(taskCode);
            //增加验证
            if("finish".equals(task.getStatus())){
                resultMap.put("msg", "该任务已经点收完成，请核查！");
                return resultMap;
            }
            task.setStatus("doing");
            
            //设置点收数据
            List<InstorageCountItem> itemList=instorageCountItemDao.loadByBillCode(task.getBillCode());
            InstorageCountItem currItem = null;
            boolean flag=false;
            resultMap.put("newFlag", "no");
            for (InstorageCountItem _item : itemList) {
                String _sku=_item.getSku();
                String _errorFlag = _item.getErrorFlag();
                if(sku.equals(_sku)&&errorFlag.equals(_errorFlag)){
                    _item.setNum(_item.getNum()+num);
                    currItem = _item;
                    flag=true;
                    break;
                }
            }
            
            if(flag==false){
                InstorageCountItem item=new InstorageCountItem();
                currItem = item;
                item.setBillCode(task.getBillCode());
                item.setCustomerCode(task.getCustomerCode());
                item.setInstorageType("box");
                item.setNum(num);
                item.setSku(sku);
                item.setUpStatus("unup");
                item.setUpNum(0);
                item.setTaskCode(taskCode);
                item.setWarehouseCode(task.getWarehouseCode());
                item.setErrorFlag(errorFlag);
                itemList.add(item);
                resultMap.put("newFlag", "yes");
            }

            int count  = 0 ;
            int preCount = 0;
            for(InstorageCountItem _item : itemList){
                String _sku = _item.getSku();
                if(sku.equals(_sku)){
                    count += _item.getNum();
                }
            }
            InstorageBillPre billPre = instorageBillPreDao.findByInBillCode(task.getBillCode());
            if(billPre != null){
                List<InstorageBillItemPre> itemPres = instorageBillItemPreDao.query(billPre.getId());
                for (InstorageBillItemPre instorageBillItemPre : itemPres) {                
                    if (sku.equals(instorageBillItemPre.getSkuCode())) {
                        preCount += instorageBillItemPre.getGoodsNum();
                        instorageBillItemPre.setCountNum(instorageBillItemPre.getCountNum()+num);
                    }
                }
                resultMap.put("preitems", itemPres);
                if(count > preCount) {
                    throw new PaiUException(InStorageBillErrorCode.COUNT_NUM_ERROR, new String[] { sku });
                }
            }
            
            this.instorageCountItemDao.save(itemList);
            resultMap.put("msg", "success");
            resultMap.put("goodNum", String.valueOf(preCount));
            return resultMap;
            
        } catch (Exception e) {
            throw e;
        }
        
    }
	
	
	@Transactional(readOnly = false, rollbackFor=Exception.class)
	public Map<String, Object> countNew2(String taskCode, String sku, Integer num, String batchCode, 
	    String productDate, String expireDate, String errorFlag) throws Exception {
		try { 
			
			Map<String, Object> resultMap = new HashMap<String, Object>();
			//修改任务状态
			InstorageCountTask task=this.instorageCountTaskDao.loadByTaskCode(taskCode);
			//增加验证
			if("finish".equals(task.getStatus())){
				resultMap.put("msg", "该任务已经点收完成，请核查！");
				return resultMap;
			}
			task.setStatus("doing");
			
			//设置点收数据
			List<InstorageCountItem> itemList=instorageCountItemDao.loadByBillCode(task.getBillCode());
			InstorageCountItem currItem = null;
			boolean flag=false;
			resultMap.put("newFlag", "no");
			for (InstorageCountItem _item : itemList) {
				String _sku=_item.getSku();
				String _batchCode = _item.getBatchCode();
				String _productDate = _item.getProductDate();
				String _expireDate = _item.getExpireDate();
				String _errorFlag = _item.getErrorFlag();
				if(sku.equals(_sku) && errorFlag.equals(_errorFlag) &&
				   (batchCode == null ? "" : batchCode).equals(_batchCode == null ? "" : _batchCode) &&
				   (productDate == null ? "" : productDate).equals(_productDate == null ? "" : _productDate)&&
				   (expireDate == null ? "" : expireDate).equals(_expireDate == null ? "" : _expireDate)){
					_item.setNum(_item.getNum()+num);
					currItem = _item;
					flag=true;
					break;
				}
			}
			
			if(flag==false){
				InstorageCountItem item=new InstorageCountItem();
				currItem = item;
				item.setBillCode(task.getBillCode());
				item.setCustomerCode(task.getCustomerCode());
				item.setInstorageType("box");
				item.setNum(num);
				item.setSku(sku);
				item.setUpStatus("unup");
				item.setUpNum(0);
				item.setTaskCode(taskCode);
				item.setWarehouseCode(task.getWarehouseCode());
				item.setErrorFlag(errorFlag);
				item.setBatchCode(batchCode);
				item.setProductDate(productDate);
				item.setExpireDate(expireDate);
				itemList.add(item);
				resultMap.put("newFlag", "yes");
			}

			int count  = 0 ;
			int preCount = 0;
			for(InstorageCountItem _item : itemList){
				String _sku = _item.getSku();
				String _batchCode = _item.getBatchCode();
				String _productDate = _item.getProductDate();
				String _expireDate = _item.getExpireDate();
				if(sku.equals(_sku) && 
				   (batchCode == null ? "" : batchCode).equals(_batchCode == null ? "" : _batchCode) &&
	               (productDate == null ? "" : productDate).equals(_productDate == null ? "" : _productDate)&&
	               (expireDate == null ? "" : expireDate).equals(_expireDate == null ? "" : _expireDate)){
					count += _item.getNum();
				}
			}
			InstorageBillPre billPre = instorageBillPreDao.findByInBillCode(task.getBillCode());
        	if(billPre != null){
        		List<InstorageBillItemPre> itemPres = instorageBillItemPreDao.query(billPre.getId());
        		for (InstorageBillItemPre instorageBillItemPre : itemPres) {       		    
					if (sku.equals(instorageBillItemPre.getSkuCode()) && 
					    (batchCode == null ? "" : batchCode).equals(instorageBillItemPre.getBatchCode() == null ? "" : instorageBillItemPre.getBatchCode()) &&
					    (productDate == null ? "" : productDate).equals(instorageBillItemPre.getProductDate() == null ? "" : instorageBillItemPre.getProductDate()) && 
					    (expireDate == null ? "" : expireDate).equals(instorageBillItemPre.getExpireDate() == null ? "" : instorageBillItemPre.getExpireDate())) {
						preCount += instorageBillItemPre.getGoodsNum();
						instorageBillItemPre.setCountNum(instorageBillItemPre.getCountNum()+num);
					}
				}
        		resultMap.put("preitems", itemPres);
        		if(count > preCount) {
        			throw new PaiUException(InStorageBillErrorCode.COUNT_NUM_ERROR, new String[] { sku });
        		}
        	}
			
			this.instorageCountItemDao.save(itemList);
			resultMap.put("msg", "success");
			resultMap.put("goodNum", String.valueOf(preCount));
			return resultMap;
			
		} catch (Exception e) {
			throw e;
		}
		
	}
	
	/**
	 * 根据入库单号，查询相应单号的预约入库SKU明细
	 * @param billCode 入库单号
	 * @return 入库预约明细
	 * @throws Exception
	 */
	public List<InstorageBillItemPre> loadBillItemPres(String billCode) throws Exception {
		List<InstorageBillItemPre> itemPres=null;
		try {
			InstorageBillPre billPre = instorageBillPreDao.findByInBillCode(billCode);
        	if(billPre != null){
        		itemPres = instorageBillItemPreDao.query(billPre.getId());
        	}
        	return itemPres;			
		} catch (Exception e) {
			throw e;
		}
	}
	
	/**
	 * 散货点收
	 * @param taskCode
	 * @param sku
	 * @return "success" 成功
	 * @throws Exception 
	 */
	@Transactional(readOnly = false, rollbackFor=Exception.class)
	public String count_single(String taskCode, String sku) throws Exception {
		try {
			
			//修改任务状态
			InstorageCountTask task=this.instorageCountTaskDao.loadByTaskCode(taskCode);
			task.setStatus("doing");
			
			//设置点收数据
			List<InstorageCountItem> itemList=instorageCountItemDao.loadByTaskCode(taskCode,"single");
			boolean flag=false;
			for (InstorageCountItem _item : itemList) {
				String _sku=_item.getSku();
				if(sku.equals(_sku)){
					_item.setNum(_item.getNum()+1);
					flag=true;
					break;
				}
			}
			if(flag==false){
				InstorageCountItem item=new InstorageCountItem();
				item.setBillCode(task.getBillCode());
				item.setCustomerCode(task.getCustomerCode());
				item.setInstorageType("single");
				item.setNum(1);
				item.setSku(sku);
				item.setUpStatus("unup");
				item.setUpNum(0);
				item.setTaskCode(taskCode);
				item.setWarehouseCode(task.getWarehouseCode());
				item.setErrorFlag(task.getErrorFlag());
				itemList.add(item);
			}
			this.instorageCountItemDao.save(itemList);
			
			return "success";
			
		} catch (Exception e) {
			throw e;
		}
		
	}

	/**
	 * 整箱点收
	 * @param taskCode
	 * @param sku
	 * @param num
	 * @param boxCode
	 * @return "success" 成功
	 * @throws Exception 
	 */
	@Transactional(readOnly = false, rollbackFor=Exception.class)
	public String count_box(String taskCode, String sku, Integer num, String boxCode) throws Exception {
       try {
			
			//修改任务状态
			InstorageCountTask task=this.instorageCountTaskDao.loadByTaskCode(taskCode);
			task.setStatus("doing");
			
			//添加点收数据
			InstorageCountItem item=new InstorageCountItem();
			item.setBillCode(task.getBillCode());
			item.setCustomerCode(task.getCustomerCode());
			item.setWarehouseCode(task.getWarehouseCode());
			item.setTaskCode(taskCode);
			item.setInstorageType("box");
			item.setSku(sku);
			item.setUpNum(0);
			item.setNum(num);
			item.setUpStatus("unup");
			item.setBoxCode(boxCode);
			item.setErrorFlag(task.getErrorFlag());
			this.instorageCountItemDao.save(item);
			
			return "success";
			
		} catch (Exception e) {
			throw e;
		}
	}
	
	/**
	 * 查询点收明细
	 * @param taskCode 任务编号
	 * @param instorageType 类型 box 整箱 single 散货
	 * @return
	 */
	public List<InstorageCountItem> loadByTaskCode(String taskCode,String instorageType) {
		return this.instorageCountItemDao.loadByTaskCode(taskCode,instorageType);
	}
	public List<InstorageCountItem> findByTaskCode(String taskCode) {
		return this.instorageCountItemDao.findByTaskCode(taskCode);
	}

	/**
	 * 删除点收明细项
	 * @param itemId
	 */
	@Transactional(readOnly = false)
	public String deleteCountItem(Long itemId) {
		InstorageCountItem item=this.instorageCountItemDao.findOne(itemId);
		InstorageCountTask tmpCountTask = instorageCountTaskDao.loadByTaskCode(item.getTaskCode()==null?"":item.getTaskCode());
		if (null != tmpCountTask && !"doing".equals(tmpCountTask.getStatus())) {
            return "error";
        }
		this.instorageCountItemDao.delete(item);
		return "success";
	}

	/**
	 * 完成点收
	 * @param taskCode
	 * @throws Exception 
	 * @return 'success'成功  
	 */
	@Transactional(readOnly = false, rollbackFor=Exception.class)
	public String finishCount(String taskCode) throws Exception {
		try {
			
			Date now=new Date();
			
			//修改任务状态
			InstorageCountTask countTask=this.instorageCountTaskDao.loadByTaskCode(taskCode);
			countTask.setStatus("finish");
			
			//修改入库单状态
			InstorageBill bill=this.instorageBillDao.loadBillByCode(countTask.getBillCode());
			bill.setStatus("3"); //入库状态 （0:待登记 (调拨货品已出库，尚未入库) 1.入库登记 2.领取点收任务 3.点收完成 4.领取上架任务 5.上架完成 ）
			this.instorageBillDao.save(bill);
			//入库日志
			InstorageLog log=new InstorageLog();
			log.setBillCode(countTask.getBillCode());
			log.setWorkerUuid(countTask.getWorkerUuid());
			User worker=this.userDao.findByJobuuid(countTask.getWorkerUuid());
			log.setInfo(worker.getRealname()+"完成点收任务");
			log.setWorkTime(now);
			log.setWorkType("finishCount"); //操作类型 ( sign.登记入库单 takeCountTask.领取点收任务 finishCount.点收完成 taskUpTask.领取上架任务 finishUp.上架完成 )
			this.instorageLogDao.save(log);
			
			List<InstorageCountItem> countItem = new ArrayList<InstorageCountItem>();
			//创建上架任务
			List<InstorageCountItem> itemList_box=this.loadByTaskCode(countTask.getTaskCode(),"box");
	        if(itemList_box.size()>0){
	        	countItem.addAll(itemList_box);
	        	InstorageUpTask upTask=new InstorageUpTask();
	        	upTask.setBillCode(countTask.getBillCode());
	        	upTask.setCreateTime(now);
	        	upTask.setCustomerCode(countTask.getCustomerCode());
	        	upTask.setStatus("undo");
	        	upTask.setTaskCode(TMSTransportRule.generateUpTaskCode());
	        	upTask.setTaskType("box");
	        	upTask.setWarehouseCode(countTask.getWarehouseCode());
	        	upTask.setErrorFlag(bill.getErrorFlag());
	        	this.instorageUpTaskDao.save(upTask);
	        	
	        	for (InstorageCountItem item : itemList_box) {
	        		item.setUptaskCode(upTask.getTaskCode());
				}
	        	this.instorageCountItemDao.save(itemList_box);
	        }
	        
	        List<InstorageCountItem> itemList_single=this.loadByTaskCode(countTask.getTaskCode(),"single");
	        if(itemList_single.size()>0){
	        	countItem.addAll(itemList_single);
	        	InstorageUpTask upTask=new InstorageUpTask();
	        	upTask.setBillCode(countTask.getBillCode());
	        	upTask.setCreateTime(now);
	        	upTask.setCustomerCode(countTask.getCustomerCode());
	        	upTask.setStatus("undo");
	        	upTask.setTaskCode(TMSTransportRule.generateUpTaskCode());
	        	upTask.setTaskType("single");
	        	upTask.setWarehouseCode(countTask.getWarehouseCode());
	        	upTask.setErrorFlag(bill.getErrorFlag());
	        	this.instorageUpTaskDao.save(upTask);
	        	
	        	for (InstorageCountItem item : itemList_single) {
	        		item.setUptaskCode(upTask.getTaskCode());
				}
	        	this.instorageCountItemDao.save(itemList_single);
	        }
	        if(PYOrderType.PRE_ORDER.getType().equals(bill.getBillType()) || PYOrderType.RETURN_ORDER.getType().equals(bill.getBillType())){
	        	//修改预约单状态
	        	InstorageBillPre billPre = instorageBillPreDao.findByInBillCode(bill.getBillCode());
	        	if(billPre != null){
	        		if(StatusEnums.PREORDER_STATUS_CANEL.getStatus().equals(billPre.getOrderStatus())){
						throw new PaiUException(ErrorCode.ORDER_CANCELED_ERROR, new String[] { bill.getBillCode() });
	        		}
	        		billPre.setOrderStatus(StatusEnums.PREORDER_STATUS_CHECK.getStatus());
	        		instorageBillPreDao.save(billPre);
	        		
	        		//校验点收是否跟预约的数量一致
	        		boolean matchFlg = checkCountNumMatchWithPre(countItem, instorageBillItemPreDao.query(billPre.getId()));
	        		bill.setMatchFlag(matchFlg ? "1" : "0");
	        		//美的的订单，如果点收于下单的不一致，不允许点收
					if (WmsContants.CUSTOMER_MID.equals(billPre.getCustomerCode()) && !matchFlg) {
	        			throw new PaiUException(ErrorCode.COUNT_ERROR);
	        		}
	        	}
	        }
	        //调拨出库校验数量是否一致
	        else if("allot".equals(bill.getBillType())){
	        	boolean matchFlg = checkCountNumMatchWithOut(countItem, outstorageBillItemDao.loadByBillCode(bill.getAboutCode()));
        		bill.setMatchFlag(matchFlg ? "1" : "0");
	        }
	        this.instorageBillDao.save(bill);
	        return "success";
			
			
		} catch (Exception e) {
			throw e;
		}
	}
	
	/**
	 * 点收新流程
	 * @param taskCode
	 * @return
	 * @throws Exception String
	 */
	@Transactional(readOnly = false, rollbackFor=Exception.class)
	public String finishCountNew(String taskCode) throws Exception {
		try {
			Date now=new Date();
			InstorageCountTask countTask=this.instorageCountTaskDao.loadByTaskCode(taskCode);
			if("finish".equals(countTask.getStatus())){
				throw new PaiUException(ErrorCode.COUNT_FINISH_ERROR);
			}
			//修改任务状态
			countTask.setStatus("finish");
			
			//修改入库单状态
			InstorageBill bill=this.instorageBillDao.loadBillByCode(countTask.getBillCode());
			bill.setStatus("3"); //入库状态 （0:待登记 (调拨货品已出库，尚未入库) 1.入库登记 2.领取点收任务 3.点收完成 4.领取上架任务 5.上架完成 ）
			this.instorageBillDao.save(bill);
			//入库日志
			InstorageLog log=new InstorageLog();
			log.setBillCode(countTask.getBillCode());
			log.setWorkerUuid(countTask.getWorkerUuid());
			User worker=this.userDao.findByJobuuid(countTask.getWorkerUuid());
			log.setInfo(worker.getRealname()+"完成点收任务");
			log.setWorkTime(now);
			log.setWorkType("finishCount"); //操作类型 ( sign.登记入库单 takeCountTask.领取点收任务 finishCount.点收完成 taskUpTask.领取上架任务 finishUp.上架完成 )
			this.instorageLogDao.save(log);
			
			//生成上架分配任务
			InstorageUpDispatchTask disTask = new InstorageUpDispatchTask();
			disTask.setInstorageBill(bill);
			disTask.setStatus("0");//0:未处理 1:已领取 2:已分配
			disTask.setTaskCode(TMSTransportRule.generateDispatchTaskCode());
			instorageUpDispatchTaskDao.save(disTask);
			
	        if(PYOrderType.PRE_ORDER.getType().equals(bill.getBillType()) || PYOrderType.RETURN_ORDER.getType().equals(bill.getBillType())){
	        	//修改预约单状态
	        	InstorageBillPre billPre = instorageBillPreDao.findByInBillCode(bill.getBillCode());
	        	if(billPre != null){
	        		if(StatusEnums.PREORDER_STATUS_CANEL.getStatus().equals(billPre.getOrderStatus())){
						throw new PaiUException(ErrorCode.ORDER_CANCELED_ERROR, new String[] { bill.getBillCode() });
	        		}
	        		billPre.setOrderStatus(StatusEnums.PREORDER_STATUS_CHECK.getStatus());
	        		instorageBillPreDao.save(billPre);
	        		
	        		List<InstorageCountItem> countItems = new ArrayList<InstorageCountItem>();
	        		for (PreInBill preInBill : billPre.getPreInBills()) {
	        			countItems.addAll(findByBillCode(preInBill.getInBillCode()));
					}
	        		//校验点收是否跟预约的数量一致
	        		boolean matchFlg = checkCountNumMatchWithPre(countItems, instorageBillItemPreDao.query(billPre.getId()));
					for (PreInBill preInBill : billPre.getPreInBills()) {
						InstorageBill instorageBill = instorageBillDao.loadBillByCode(preInBill.getInBillCode());
						instorageBill.setMatchFlag(matchFlg ? "1" : "0");
						instorageBillDao.save(instorageBill);
					}
	        		
	        		//美的的订单，如果点收于下单的不一致，不允许点收
	        		if (WmsContants.CUSTOMER_MID.equals(billPre.getCustomerCode()) && !matchFlg && PYOrderType.RETURN_ORDER.getType().equals(bill.getBillType())) {
	        			throw new PaiUException(ErrorCode.COUNT_ERROR);
	        		}
	        	}
	        }
	        //调拨出库校验数量是否一致
	        else if("allot".equals(bill.getBillType())){
	        	boolean matchFlg = checkCountNumMatchWithOut(findByBillCode(bill.getBillCode()), outstorageBillItemDao.loadByBillCode(bill.getAboutCode()));
        		bill.setMatchFlag(matchFlg ? "1" : "0");
	        }
	        this.instorageBillDao.save(bill);
	        return "success";
			
		} catch (Exception e) {
			throw e;
		}
	}
	
	private boolean checkCountNumMatchWithPre(List<InstorageCountItem> countItem, List<InstorageBillItemPre> preItem){
		boolean rs = true;
		Map<String,Integer> countMap = new HashMap<String, Integer>(countItem.size());
		Map<String,Integer> countPreMap = new HashMap<String, Integer>(countItem.size());
		for (InstorageCountItem instorageCountItem : countItem) {
			String countSku = instorageCountItem.getSku();
			Integer countNum = instorageCountItem.getNum();
			Integer countAmt = countMap.get(countSku);
			countMap.put(countSku, countAmt == null ? countNum : countAmt + countNum);
		}
		for (InstorageBillItemPre instorageBillItemPre : preItem) {
			String countSku = instorageBillItemPre.getSkuCode();
			Integer countNum = instorageBillItemPre.getGoodsNum();
			Integer countAmt = countPreMap.get(countSku);
			countPreMap.put(countSku, countAmt == null ? countNum : countAmt + countNum);
		}
		for (Map.Entry<String, Integer> entry : countPreMap.entrySet()) {
			String key = entry.getKey();
			Integer preValue = entry.getValue();
			Integer countValue = countMap.get(key);
			if (countValue == null || !countValue.equals(preValue)) {
				rs = false;
			}
		}
		return rs && countPreMap.size() == countMap.size();
	}
	private boolean checkCountNumMatchWithOut(List<InstorageCountItem> countItem, List<OutstorageBillItem> outItem){
		boolean rs = true;
		Map<String,Integer> countMap = new HashMap<String, Integer>(countItem.size());
		Map<String,Integer> countOutMap = new HashMap<String, Integer>(outItem.size());
		for (InstorageCountItem instorageCountItem : countItem) {
			String countSku = instorageCountItem.getSku();
			Integer countNum = instorageCountItem.getNum();
			Integer countAmt = countMap.get(countSku);
			countMap.put(countSku, countAmt == null ? instorageCountItem.getNum() : countAmt + countNum);
		}
		for (OutstorageBillItem outstorageBillItem : outItem) {
			String countSku = outstorageBillItem.getSku();
			Integer countNum = outstorageBillItem.getNum();
			Integer countAmt = countOutMap.get(countSku);
			countOutMap.put(countSku, countAmt == null ? countNum : countAmt + countNum);
		}
		for (Map.Entry<String, Integer> entry : countOutMap.entrySet()) {
			String key = entry.getKey();
			Integer outValue = entry.getValue();
			Integer countValue = countMap.get(key);
			if (countValue == null || !countValue.equals(outValue)) {
				rs = false;
			}
		}
		return rs && countOutMap.size() == countMap.size();
	}
	
	/**
	 * 查询上架任务
	 * @param taskCode 上架任务号
	 * @return
	 */
	public List<InstorageCountItem> loadByUpTaskCode(String uptaskCode) {
		return this.instorageCountItemDao.loadByUpTaskCode(uptaskCode);
	}
	/**
	 * 查询点收任务
	 * @param billCode 入库单
	 * @return
	 */
	public List<InstorageCountItem> findByBillCode(String billCode) {
		return this.instorageCountItemDao.loadByBillCode(billCode);
	}

	/**
	 * 查询点收任务
	 * @param billCode
	 * @return
	 */
	public InstorageCountTask loadByBillCode(String billCode) {
		return this.instorageCountTaskDao.loadByBillCode(billCode);
	}
	
	/**
	 * 查找未分配任务的商品
	 * @param taskCode
	 * @return List<InstorageCountItem>
	 */
	public List<InstorageCountItem> unUpItem(String taskCode) {
		InstorageUpTask upTask = instorageUpTaskDao.loadByTaskCode(taskCode);
		List<InstorageCountItem> countItems = instorageCountItemDao.loadByBillCode(upTask.getBillCode());
		Map<String, Integer> countMap = EdiOrderUtil.count(countItems);
		
		List<InstorageUpTaskItem> upTaskItems = instorageUpTaskItemDao.findByUpTaskCode(taskCode);
		Map<String, Integer> upTaskItemMap = EdiOrderUtil.countInstorageUpTaskItem(upTaskItems);
		
		List<InstorageCountItem> rs = new ArrayList<InstorageCountItem>();
		for (Map.Entry<String, Integer> entry : countMap.entrySet()){
			String [] sku_error = entry.getKey().split("_");
			String sku = entry.getKey();
			String errorflag = sku_error[1];
			Integer num = entry.getValue();
			InstorageCountItem item  = new InstorageCountItem();
			item.setSku(sku);
			item.setNum(num);
			item.setErrorFlag(errorflag);
			Integer upNum = upTaskItemMap.get(sku);
			item.setUpNum(upNum == null ? 0 : upNum);
			rs.add(item);
		}
		Collections.sort(rs, new Comparator<InstorageCountItem>() {
			@Override
			public int compare(InstorageCountItem o1, InstorageCountItem o2) {
				return (o2.getNum() - o2.getUpNum()) == 0 ? -1 :
					(o1.getNum() - o1.getUpNum()) == 0 ? 1 :
					(Integer.compare(o1.getNum() - o1.getUpNum(), o2.getNum() - o2.getUpNum()));
			}
			
		});
		return rs;
	}
	
	public String findSkuExist(String billCode,String skuCode,String customerCode){
        //查找是否存在预约单
        InstorageBillPre bp = instorageCountTaskDao.findInstorageBillPreExist(billCode);
        if(bp != null) {
            //查找预约入库中是否存在skuCode
            List<InstorageBillItemPre> ip = instorageCountTaskDao.findSkuExist(bp.getBillCode(), skuCode);
            if(ip == null||ip.size()==0){
                return "SKU:"+skuCode+" 在该预约单不存在";
            }
        }else {
            //如果不存在去edi_goods_sku表找
            EdiGoodsSku sku = ediGoodsSkuDao.findByCustomerCodeAndSku(customerCode, skuCode);
            //add LiBin bug617 防止界面输入的数据和数据库中存在大小写的区别
            if(sku==null || !sku.getSku().equals(skuCode)){
                return "请确认SKU是否存在,或查看大小写!";
            }
        }
        return null;
        
    }
	
	public String findSkuExistNew(String billCode,String skuCode,String customerCode, String batchCode, String productDate, String expireDate){
		//查找是否存在预约单
		InstorageBillPre bp = instorageCountTaskDao.findInstorageBillPreExist(billCode);
		if(bp != null) {
			//查找预约入库中是否存在skuCode
			List<InstorageBillItemPre> ip = instorageCountTaskDao.findSkuExistNew(bp.getBillCode(), skuCode, batchCode, productDate, expireDate);
			if(ip == null||ip.size()==0){
				return "SKU:"+skuCode+" 在该预约单不存在";
			}
		}else {
			//如果不存在去edi_goods_sku表找
			EdiGoodsSku sku = ediGoodsSkuDao.findByCustomerCodeAndSku(customerCode, skuCode);
			if(sku==null){
				return "请确认SKU是否存在 ";
			}
		}
		return null;
		
	}
	
	/**
     * 获取sku批次信息
     * @param billCode sku
     * @return
     */
    public List<Map<String,Object>> batchList(String billCode,String sku){
        String sql = "select distinct ip.batch_code, ip.product_date, ip.expire_date"
            + " from instorage_bill b,"
            + " instorage_bill_pre p,"
            + " instorage_bill_item_pre ip "
            + " where b.bill_code = '" + billCode + "' "
            + " and b.about_code = p.bill_code and ip.bill_pre_id = p.id "
            + " and ip.sku_code = '" + sku + "' order by ip.product_date desc";
        return jdbcTemplate.queryForList(sql);
    }
}